#include <linux/skbuff.h>

#include "rxe.h"
#include "rxe_loc.h"

static int check_type_state(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
        struct rxe_qp *qp)
{
    unsigned int pkt_type;
    if(unlikely(!qp->valid))
        goto err1;

    /*高3bit是qp类型*/
    pkt_type = pkt->opcode & 0xe0;

    switch(qp_type(qp)) {
        case IB_QPT_RC:
            if(unlikely(pkt_type != IB_OPCODE_RC)) {
                goto err1;
            }
            break;
        case IB_QPT_UC:
            if (unlikely(pkt_type != IB_OPCODE_UC)) {
                pr_warn_ratelimited("bad qp type\n");
                goto err1;
            }
            break;
        case IB_QPT_UD:
        case IB_QPT_SMI:
        case IB_QPT_GSI:
            if (unlikely(pkt_type != IB_OPCODE_UD)) {
                pr_warn_ratelimited("bad qp type\n");
                goto err1;
            }
            break;
        default:
            pr_warn_ratelimited("unsupported qp type\n");
            goto err1;
    }

    if (pkt->mask & RXE_REQ_MASK) {
        if (unlikely(qp->resp.state != QP_STATE_READY))
            goto err1;
    } else if (unlikely(qp->req.state < QP_STATE_READY ||
            qp->req.state > QP_STATE_DRAINED)) {
            goto err1;
    }

    return 0;
err1:
    return -EINVAL;
}

static void set_bad_pkey_cntr(struct rxe_port *port)
{


}

static void set_qkey_viol_cntr(struct rxe_port *port)
{


}

static int check_keys(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
    u32 qpn, struct rxe_qp *qp)
{
    struct rxe_port *port = &rxe->port;
    u16 pkey = bth_pkey(pkt);




    return 0;
err1:
    return -EINVAL;
}

static int check_addr(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
        struct rxe_qp *qp)
{
    struct sk_buff *skb = PKT_TO_SKB(pkt);

done:
    return 0;
err1:
    return -EINVAL;
}

static int hdr_check(struct rxe_pkt_info *pkt)
{
    struct rxe_dev *rxe = pkt->rxe;
    struct rxe_port *port = &rxe->port;
    struct rxe_qp *qp = NULL;
    u32 qpn = bth_qpn(pkt);
    int index;
    int err;


    if (unlikely(bth_tver(pkt) != BTH_TVER)) {
        pr_warn_ratelimited("bad tver\n");
        goto err1;
    }

    if (unlikely(qpn == 0)) {
        pr_warn_once("QP 0 not supported");
        goto err1;
    }






    return 0;
err2:
    rxe_drop_ref(qp);
err1:
    return -EINVAL;
}

static inline void rxe_rcv_pkt(struct rxe_pkt_info *pkt, struct sk_buff *skb)
{
    if (pkt->mask & RXE_REQ_MASK) {
        rxe_resp_queue_pkt(pkt->qp, skb);
    } else {
        rxe_comp_queue_pkt(pkt->qp, skb);
    }
}

static void rxe_rcv_mcast_pkt(struct rxe_dev *rxe, struct sk_buff *skb)
{
    struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
    struct rxe_mc_grp *mcg;
    struct rxe_mc_elem *mce;
    struct rxe_qp *qp;
    union ib_gid dgid;
    int err;



}

static int rxe_chk_dgid(struct rxe_dev *rxe, struct sk_buff *skb)
{
    struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
    const struct ib_gid_attr *gid_attr;
    union ib_gid dgid;
    union ib_gid *pdgid;





    return 0;
}

/* rxe_rcv is called from the interface driver */
void rxe_rcv(struct sk_buff *skb)
{
    int err;
    //取出skb的私有数据
    struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
    struct rxe_dev *rxe = pkt->rxe;

    if(unlikely(skb->len < RXE_BTH_BYTES))
        goto drop;

    if(rxe_chk_dgid(rxe, skb) < 0) {
        goto drop;
    }

    pkt->opcode = bth_opcode(pkt);
    pkt->psn = bth_psn(pkt);
    pkt->qp = NULL;
    pkt->mask | = rxe_opcode[pkt->opcode].mask;

    /*根据opcode类型取出包头的数据长度*/
    if (unlikely(skb->len < header_size(pkt)))
        goto drop;

    /**/
    err = hdr_check(pkt);
    if(unlikely(err))
        goto drop;

    err = rxe_icrc_check(skb, pkt);
    if(unlikely(err))
        goto drop;

    rxe_counter_inc(rxe, RXE_CNT_RCVD_PKTS);

    /**/
    if (unlikely(bth_qpn(pkt) == IB_MULTICAST_QPN))
        rxe_rcv_mcast_pkt(rxe, skb);
    else
        rxe_rcv_pkt(pkt, skb);

    return;
drop:
    if(pkt->qp)
        rxe_drop_ref(pkt->qp);

    kfree_skb(skb);
    ib_device_put(&rxe->ib_dev);
}
